import { getObjectValue } from '../utils/ObjectUtils';
import { constructVnode } from './mount';

// 通过模板，找到哪些节点用到了这个模板
let templateToNode = new Map();
// 通过节点，找到那个节点下有这个模板
let vnodeToTemplate = new Map();

// 注册render方法
export function renderMinix(MiniVue) {
    // 原型上添加render方法
    MiniVue.prototype.$render = function() {
        // 调用render后渲染节点
        return renderNode(this, this._vnode);
    }
}

/**
 * data中数据发生变化立即重新渲染
 * @param {MiniVue} vm 
 * @param {VNode} vnode 
 */
export function renderData(vm, data) {
    // 获取当前data关联的vnode数据
    const nodes = templateToNode.get(data)
    nodes && nodes.forEach((node)=> {
        renderNode(vm, node)
    })
}

/**
 * 渲染Node
 * @param {MiniVue} vm 
 * @param {*} vnode 
 * @returns 
 */
export function renderNode(vm, vnode) {
    return new Promise((resolve) => {
        // 如果节点是文本节点
        if(vnode.nodeType == 3) {
            let result = vnode.text;
            // 获取当前节点关联的模板
            let templateArray = vnodeToTemplate.get(vnode);
            // 如果当前节点里面有模板
            templateArray?.forEach(template => {
                // 从Data或者env中获取模板中的值
                let templateValue = getTemplateValue([vnode.env, vm._data], template); // 获取模板中的值
                // 将模板中的值替换到节点中
                if(templateValue) {
                    result = result.replace("{{" + template + "}}", templateValue);
                }
            })
            vnode.ele.nodeValue = result;
        } else if (vnode.nodeType == 1 && vnode.tag == 'INPUT') {
            // 获取当前节点关联的模板
            let templateArray = vnodeToTemplate.get(vnode);
            // 如果当前节点里面有模板并遍历
            templateArray?.forEach(template => {
                // 从Data或者env中获取模板中的值
                let templateValue = getTemplateValue([vm._data, vnode.env], template); // 获取模板中的值
                // 将模板中的值替换到节点中
                templateValue && (vnode.ele.value = templateValue);
            })
        } else { // 如果不是文本节点就循环寻找子节点
            vnode.children.forEach(child => {
                renderNode(vm, child);
            })
        }
        resolve()
    })
}

/**
 * 准备渲染（收集依赖）
 * @param {MiniVue} vm
 * @param {VNode} vnode
 */
export function prepareRender(vm, vnode) {
    if(vnode == null) {
        return null;
    }
    // 如果是文本节点
    if(vnode.nodeType == 3) {
        // 解析文本节点，并记录模板与节点之间的关系
        analysisTemplateString(vnode);
    }
    // 如果是元素节点
    if(vnode.nodeType == 1) {
        analysisAttr(vm, vnode);
    }
    // 收集虚拟节点的依赖
    if (vnode.nodeType == 0) {
        setTemplateToVnode("{{" + vnode.data + "}}", vnode);
        setVnodeToTemplate("{{" + vnode.data + "}}", vnode);
    }
    // 循环遍历子节点
    for (let i = 0 ; i < vnode.children.length ; i ++) {
        prepareRender(vm, vnode.children[i]);
    }
}

export function rebuild(vm, data) {
    // 获取当前data关联的vnode数据
    const nodes = templateToNode.get(data)
    nodes && nodes.forEach((node)=> {
        // 清空父级的innerHTML
        node.parent.ele.innerHTML = ""
        // 重新设置父级的html
        node.parent.ele.appendChild(node.ele)
        // 重新渲染节点
        const vnode = constructVnode(vm, node.ele, node.parent)
        // 给父级（UL）添加children
        node.parent.children = [vnode]
        // 清空失效的依赖
        clearMap()
        // 重新收集依赖
        prepareRender(vm, vm._vnode)
        // 重新渲染节点
        renderNode(vm, vnode)
    })
}

function clearMap() {
    templateToNode.clear()
    vnodeToTemplate.clear()
}

/**
 * 解析文本节点

 * @param {MiniVue} vm 
 * @param {String} text 
 */
function analysisTemplateString(vnode) {
    let templateArray = vnode.text.match(/{{[a-zA-Z0-9_.]+}}/g)
    templateArray?.forEach(template => {
        setTemplateToVnode(template, vnode);
        setVnodeToTemplate(template, vnode);
    })
}


function analysisAttr(vm, vnode) {
    if (vnode.nodeType != 1) {
        return;
    }
    let attrNames = vnode.ele.getAttributeNames();
    if (attrNames.includes("v-model")) {
        setTemplateToVnode("{{" + vnode.ele.getAttribute("v-model") + "}}", vnode);
        setVnodeToTemplate("{{" + vnode.ele.getAttribute("v-model") + "}}", vnode);
    }
}

function setTemplateToVnode(template, vnode) {
    template = getTemplateName(template);
    // 如果存在，则将当前节点添加到模板中
    templateToNode.has(template) ? templateToNode.get(template).push(vnode) : templateToNode.set(template, [vnode]);
}

function setVnodeToTemplate(template, vnode) {
    template = getTemplateName(template);
    // 如果存在，则将当前模板添加到节点中
    vnodeToTemplate.has(vnode) ? vnodeToTemplate.get(vnode).push(template) : vnodeToTemplate.set(vnode, [template]);
}

// 去掉模板中的花括号
function getTemplateName(template) {
    return template.replace(/{{|}}/g, '');
}

// 获取文本中的模板
function getTemplateValue(objs, template) {
    for(let i = 0; i < objs.length; i++) {
        let templateValue = getObjectValue(objs[i], template);
        if(templateValue != null) {
            return templateValue;
        }
    }
    return null;
}

